// ParticleSystem.h: interface for the CParticleSystem class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_PARTICLESYSTEM_H__70477B21_7DD0_11D5_AD0F_507157C10000__INCLUDED_)
#define AFX_PARTICLESYSTEM_H__70477B21_7DD0_11D5_AD0F_507157C10000__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#pragma pack(4)
typedef struct _tag_PARTICLEVERTEX
{
	he3d_CVector	p;
	FLOAT			size;
	DWORD			color;

} PARTICLEVERTEX, *PPARTICLEVERTEX;
#pragma pack()

#define FVF_PARTICLEVERTEX D3DFVF_XYZ | D3DFVF_PSIZE | D3DFVF_DIFFUSE

enum PARTICLETYPES
{
	PT_STANDARD			= 1,
	PT_SINGLEPOINT		= 1,
	PT_BLURED			= 2,
	PT_SPARK			= 4,
	PT_EMITSSPARKS		= 8,
	PT_FORCE_DWORD		= 0x7fffffff
};

enum GRAVITY
{
	G_POINT				= 0,
	G_VECTOR			= 1,
	G_FORCE_DWORD		= 0x7fffffff
};

enum COLLISION
{
	C_OFF				= 0,
	C_PLANE				= 1,
	C_FORCE_DWORD		= 0x7fffffff
};

enum RENDERTYPE
{
	RT_ADD				= 0,
	RT_SUB				= 1
};

typedef struct _PARTICLE
{	
		he3d_CVector				vP0;
		he3d_CVector				vV0;
		he3d_CVector				vP;
		he3d_CVector				vV;

		FLOAT						fBornTime;
		FLOAT						fLifeTime;

		FLOAT						fSize;

		FLOAT						fFade;

		DWORD						dwType;

		_PARTICLE*					next;
} PARTICLE, *PPARTICLE;

class CParticleSystem;

class CBaseParticleEmiter
{
protected:

	DWORD					m_dwAvgEmitCount;
	DWORD					m_dwVarEmitCount;

	DWORD					m_dwType;
	CParticleSystem*		m_ppsSystem;	

	FLOAT					m_fAvgVelocity;
	FLOAT					m_fVarVelocity;

	FLOAT					m_fAvgLifeTime;
	FLOAT					m_fVarLifeTime;

	FLOAT					m_fAvgSize;
	FLOAT					m_fVarSize;			

	FLOAT					m_fEmitInterval;
	FLOAT					m_fLastEmitTime;	

	virtual VOID Emit( FLOAT fTime ) = 0;

	VOID Attach( CParticleSystem* pSystem );
	VOID Detach();

public:

	CBaseParticleEmiter( DWORD dwCount, DWORD dwVar, FLOAT fVel, FLOAT fVarVel, FLOAT fLife, FLOAT fVarLifer, FLOAT fSize, FLOAT fVarSize, DWORD dwType );
	CBaseParticleEmiter();
	~CBaseParticleEmiter();

	VOID SetParticleType( DWORD dwType );
	DWORD GetParticleType();
	VOID SetVelocity( FLOAT fAvgVelocity, FLOAT fVarVelocity );
	VOID GetVelocity( FLOAT& fAvgVelocity, FLOAT& fVarVelocity );
	VOID SetLifeTime( FLOAT fAvgLifeTime, FLOAT fVarLifeTime );
	VOID GetLifeTime( FLOAT& fAvgLifeTime, FLOAT& fVarLifeTime );
	VOID SetEmitCount( DWORD dwAvgEmitCount, DWORD dwVarEmitCount );
	VOID GetEmitCount( DWORD& dwAvgEmitCount, DWORD& dwVarEmitCount );
	VOID SetSize( FLOAT fAvgSize, FLOAT fVarSize );
	VOID GetSize( FLOAT& fAvgSize, FLOAT& fVarSize );
	VOID SetEmitInterval( FLOAT fTime );		
	FLOAT GetEmitInterval();
	FLOAT GetLastEmitTime();		

	friend class CParticleSystem;
};

class CPointEmiter : public CBaseParticleEmiter
{
protected:		

	he3d_CVector			m_vEmiterPos;
	he3d_CVector			m_vEmiterDir;
	FLOAT					m_fEmitAngle;

	virtual VOID Emit( FLOAT fTime );

public:
	
	CPointEmiter( DWORD dwCount, DWORD dwVar, FLOAT fVel, FLOAT fVarVel, FLOAT fLife, FLOAT fVarLifer, FLOAT fSize, FLOAT fVarSize, DWORD dwType, he3d_CVector& vPos, he3d_CVector& vDir, FLOAT fAngle );
	CPointEmiter();
	~CPointEmiter();	

	
	VOID SetEmiterPos( he3d_CVector& v );
	he3d_CVector GetEmiterPos();
	VOID SetEmiterDir( he3d_CVector& v );
	he3d_CVector GetEmiterDir();
	VOID SetEmitAngle( FLOAT fAngle );
	FLOAT GetEmitAngle();				
};

class CFinitePointEmiter : public CPointEmiter
{
protected:

	DWORD					m_dwDimension;
	DWORD					m_dwEmitedCount;

	BOOL					m_bAutoDelete;

	virtual VOID Emit( FLOAT fTime );

public:

	CFinitePointEmiter( DWORD dwCount, DWORD dwVar, FLOAT fVel, FLOAT fVarVel, FLOAT fLife, FLOAT fVarLifer, FLOAT fSize, FLOAT fVarSize, DWORD dwType, DWORD dwDim, he3d_CVector& vPos, he3d_CVector& vDir, FLOAT fAngle );
	CFinitePointEmiter();
	~CFinitePointEmiter();

	VOID SetDimension( DWORD dwDim );
	DWORD GetDimension();
	DWORD GetEmitedCount();
	VOID EnableAutoDelete( BOOL bEnable );
};

class CSphericalEmiter : public CBaseParticleEmiter
{
protected:
		
	he3d_CVector			m_vCenter;
	FLOAT					m_fRadius;

	virtual VOID Emit( FLOAT fTime );

public:

	CSphericalEmiter( DWORD dwCount, DWORD dwVar, FLOAT fVel, FLOAT fVarVel, FLOAT fLife, FLOAT fVarLifer, FLOAT fSize, FLOAT fVarSize, DWORD dwType, he3d_CVector& vCenter, FLOAT fRadius );
	CSphericalEmiter();
	~CSphericalEmiter();

	VOID SetCenter( he3d_CVector& vCenter );
	he3d_CVector GetCenter();
	VOID SetRadius( FLOAT fRadius );
	FLOAT GetRadius();
};

class CPlanarEmiter	: public CBaseParticleEmiter
{
protected:
	
	FLOAT					m_fHeight;
	FLOAT					m_fSize;

	he3d_CVector			m_vDir;

	virtual VOID Emit( FLOAT fTime );

public:

	CPlanarEmiter( DWORD dwCount, DWORD dwVar, FLOAT fVel, FLOAT fVarVel, FLOAT fLife, FLOAT fVarLifer, FLOAT fSize, FLOAT fVarSize, DWORD dwType, he3d_CVector& vDir, FLOAT fPlaneSize, FLOAT fHeight );
	CPlanarEmiter();
	~CPlanarEmiter();

	VOID SetEmiterSize( FLOAT fSize );
	FLOAT GetEmiterSize();
	VOID SetHeight( FLOAT fHeight );
	FLOAT GetHeight();
	VOID SetDir( he3d_CVector& vDir );
	he3d_CVector GetDir();
};


class CParticleSystem  
{
private:	

	DWORD					m_dwGravityType;
	FLOAT					m_fGravity;	
	he3d_CVector			m_vGravity;	

	PDIRECT3DVERTEXBUFFER8	m_pvbParticle;

	PPARTICLE				m_pParticle;
	PPARTICLE				m_pParticleFree;

	DWORD					m_dwMaxParticles;
	DWORD					m_dwParticleCount;
	DWORD					m_dwCurrentOffset;

	DWORD					m_dwBufferSize;
	DWORD					m_dwLockSize;	

	FLOAT					m_fBlurCoeff;	

	// collision sparks config	
	DWORD					m_dwSparksEmitCount;
	FLOAT					m_fSparksFalloff;
	FLOAT					m_fSparksEmitAngle;
	FLOAT					m_fSparksLifeTime;
	FLOAT					m_fSparksSize;

	// texture
	PDIRECT3DTEXTURE8		m_ptextTexture;

	// colision type
	DWORD					m_dwCollision;	

	DWORD					m_dwRenderType;
	
	// plane
	he3d_CVector			m_vN;
	FLOAT					m_fD;	

	class CEmiterListNode
	{
	public:

		CBaseParticleEmiter*	m_pEmiter;
		CEmiterListNode*		m_pNext;
	};

	CEmiterListNode*		m_pRoot;

public:

	CParticleSystem( DWORD dwMaxParticles = 4096, DWORD dwBufferSize = 1024, DWORD dwLockSize = 256 );
	virtual ~CParticleSystem();

	BOOL Initialize( PDIRECT3DDEVICE8 pDevice );

	VOID AddEmiter( CBaseParticleEmiter* pEmiter );
	VOID RemoveEmiter( CBaseParticleEmiter* pEmiter );

	VOID ConfigureSparks( DWORD dwCount, FLOAT fFalloff, FLOAT fAngle, FLOAT fLifeTime, FLOAT fSize );
	
	VOID SetCollision( DWORD dwCollision );
	DWORD GetCollison();

	VOID SetPlane( he3d_CVector& n, FLOAT d );
	VOID ConfigureGravity( DWORD dwType, he3d_CVector& vDir, FLOAT fG );	

	VOID SetTexture( PDIRECT3DTEXTURE8 ptext );
	PDIRECT3DTEXTURE8 GetTexture();

	VOID SetBlurCoeff( FLOAT fCoeff );
	FLOAT GetBlurCoeff();
	
	VOID SetRenderType( DWORD dwType );
	DWORD GetRenderType();

	VOID Update( FLOAT fTime );
	BOOL Render( PDIRECT3DDEVICE8 pDevice );

	friend class CPointEmiter;
	friend class CFinitePointEmiter;
	friend class CSphericalEmiter;
	friend class CPlanarEmiter;
};

#endif // !defined(AFX_PARTICLESYSTEM_H__70477B21_7DD0_11D5_AD0F_507157C10000__INCLUDED_)
